var stacks = require('..'),
    assert = require('assert');

describe('Stacks', function() {
  describe('#listen()', function() {
    it('should listen', function(done) {
      stacks.listen(3000, done);
    });
    it('should enable stacks.request', function() {
      stacks.request('echo', 'echo this', function(error, string) {});
    });
    it('should accept stacks clients', function(done) {
      stacks.connect(3000, function(client) {
        stacks.disconnect();
        done();
      });
    });
  });
  describe('#connect()', function() {
    it('should connect to stacks server', function(done) {
      stacks.connect(3000, function(client) {
        stacks.disconnect();
        done();
      });
    });
    it('should set stacks._client', function() {
      stacks.connect(3000, function(client) {
        assert(typeof stacks._client != 'undefined');
        stacks.disconnect();
      });
    });
    it('should call back with client (an actor)', function(done) {
      stacks.connect(3000, function(client) {
        assert(typeof client != undefined, 'client is undefined');
        assert(typeof client.on === 'function', 'client has no method `on`')
        stacks.disconnect();

        done();
      });
    });
  });
  describe('Client', function() {
    describe('#disconnect()', function() {
      it('should disconnect the from stacks server without error', function() {
        stacks.connect(3000, function(client) {
          stacks.disconnect();
        });
      });
      it('should delete stacks._client', function() {
        stacks.connect(3000, function() {
          stacks.disconnect();
          assert(typeof stacks._client === 'undefined');
        });
      });
    });
    describe('#on()', function() {
      it('should process requests of the specified type', function(done) {
        stacks.connect(3000, function(client) {
          var echoString = 'echo this';
          stacks.request('echo', echoString, function(error, string) {
            assert(string === echoString, 'echo failed to reply with identical string');

            stacks.disconnect();

            done(error);
          });
          client.on('echo', function(string, reply) {
            var error = null,
                string = string;

            reply(error, string);
          });
        });
      });
    });
  });
  describe('server', function() {
    describe('with no connected clients', function() {
      it('should keep requests on backup stacks until first client connects', function(done) {
        assert(! stacks._client, 'stacks already had a client – test invalid');

        stacks.request('echo', 'hey, how are you?', function(error, string) {});
        stacks.connect(3000, function(client) {
          client.on('echo', function(string, reply) {
            var error = null;
            reply(error, string);

            stacks.disconnect();

            done();
          });
        });
      });
    });
    it('should re-request requests that were pending on a client that disconnected', function(done) {
      var waited = false,
          error = null;

      stacks.request('wait ms', 1000, function(error, waited) {
        if (! error & waited) {
          done();
          stacks.disconnect();
        }
      });
      stacks.connect(3000, function(client) {
        client.on('wait ms', function(ms, reply) {
          setTimeout(function() {
            reply(error, waited);
          }, ms);

          stacks.disconnect();

          stacks.connect(3000, function(client) {
            client.on('wait ms', function(ms, reply) {
              waited = true;
              
              reply(error, waited);
            });
          });
          
        });
      });
    });
    it('should retry failed requests (up to request options.maxRetries times)', function(done) {
      var attempts = 0;

      stacks.request('echo', 'hey, how are you?', function(error, string) {
        if (! error) {
          stacks.disconnect();

          done();
        }
      });
      stacks.connect(3000, function(client) {
        client.on('echo', function(string, reply) {
          var error = null;

          if (++attempts <= 2) {
            error = new Error('echo error');
          }

          reply(error, string);

        });
      });
    });
  });
});